using System.Collections.Generic;
using GameFramework.Battle.Core;
using Gameplay.PVE.Config;
using Gameplay.PVE.Data;
using Gameplay.PVE.Entity;
using UnityEngine;
using Yoozoo.Libs;

namespace Gameplay.PVE.Skill
{
    //触发被动技能
    public class SkillPassiveTrigger : IClass
    {
        private Dictionary<int,SkillBase> skills = new Dictionary<int,SkillBase>();

        private Dictionary<int,SkillBase> attackSequenceSkills = new Dictionary<int, SkillBase>();

        private int currentAttackSequenceIndex;
        
        private List<SkillBase> readyList = new List<SkillBase>();

        private List<PveSkillConfig> everyFrameCheckList = new List<PveSkillConfig>();
        
        private UnitBase unit;

        private int shootTimes;
        
        private int getShootTimes;

        private ElementSystem elementSystem;

        private float bornTime;
        
        //用于计算下一次hp损失的临界线
        private Dictionary<int, List<float>> hpLostLines = new Dictionary<int, List<float>>(); 
        
        void IClass.OnReset()
        {
            hpLostLines.Clear();
            skills.Clear();
            attackSequenceSkills.Clear();
            unit = null;
            readyList.Clear();
            everyFrameCheckList.Clear();
            shootTimes = 0;
            getShootTimes = 0;
        }

        public void Initialize(UnitBase unit,ElementSystem elementSystem)
        {
            currentAttackSequenceIndex = 0;
            lastEnemyBesideCount = 0;
            this.unit = unit;
            this.elementSystem = elementSystem;
        }
        
        public void AddSkillPassive(int id,SkillBase skill)
        {
            if (unit.Data.attackSequenceSkills.Contains(id) && skill is SkillAuto)
            {
                attackSequenceSkills.Add(id,skill);
                return;
            }
            skills.Add(id,skill);
            if (skill.config.trigger_type == 13 || skill.config.trigger_type == 15)
            {
                everyFrameCheckList.Add(skill.config);
            }
            else if (skill.config.trigger_type == 4)//计算临界线
            {
                var list = new List<float>();
                float currentHpPercent = 1;
                var lostPercent = skill.config.GetTriggerParam(0) / 10000f;
                if (lostPercent > 0)
                {
                    while (true)
                    {
                        currentHpPercent -= lostPercent;
                        if (currentHpPercent <= 0)
                        {
                            break;
                        }
                        else
                        {
                            list.Add(currentHpPercent);
                        }
                    }
                    hpLostLines[id] = list;
                }

            }
        }

        public void RemoveSkillPassive(int id)
        {
            
        }

        public bool IsPassiveSkillReady()
        {
            return readyList.Count > 0;
        }

        public SkillBase CastSkill()
        {
            unit.Data.SetIsInAttack(false);
            unit.Data.SetIsInSkill(true);
            //PveFlyTextManager.Instance.ShowFlyTextPassive(readyList[0].config.desc,unit.Data.position + new Vector3(0,2.5f,0),2);
            unit.Transmit(ETransmitType.SquatUp);
            
            //对readyList进行排序
            readyList.Sort(SortPassivePriority);
            var skill = readyList[0];
            readyList[0].Play(unit.Data.position,unit.Data.forward,null,true);
            readyList.RemoveAt(0);
            return skill;
        }

        private int SortPassivePriority(SkillBase a, SkillBase b)
        {
            return unit.Data.GetPassivePriority(a.config.id).CompareTo(unit.Data.GetPassivePriority(b.config.id));
        }
        
        public void Transmit(ETransmitType type, BaseTransmitArg arg)
        {
            if (type == ETransmitType.HitOthers)
            {
                Trigger((int)ETriggerType.Hit,arg,true);
                Trigger((int)ETriggerType.SummonOnly,arg);
            }
            else if (type == ETransmitType.RPGStart)
            {
                foreach (var item in skills.Values)
                {
                    item.startTime = 0;
                }
                Trigger((int)ETriggerType.BattleStart,arg);
                Trigger((int)ETriggerType.Halo,arg);
            }
            else if (type == ETransmitType.BeforeAttack)
            {
                Trigger((int)ETriggerType.BeforeAttack,arg,true);
            }
            else if (type == ETransmitType.BeHitByOthers)
            {
                Trigger((int)ETriggerType.GetHit,arg,true);
            }
            else if (type == ETransmitType.Kill)
            {
                Trigger((int) ETriggerType.Kill, arg);
            }
            else if (type == ETransmitType.UpdateHp)
            {
                Trigger((int)ETriggerType.HpLost,arg);
            }
            else if (type == ETransmitType.Shoot)
            {
                shootTimes++;
                if (unit.Data.lockTarget == unit)
                {
                    Trigger((int)ETriggerType.ShootSelf,arg,true);
                }
                else
                {
                    Trigger((int)ETriggerType.Shoot,arg,true);
                }
            }
            else if (type == ETransmitType.Evade)
            {
                Trigger((int) ETriggerType.Evade,arg);
            }
            else if (type == ETransmitType.Critical)
            {
                Trigger((int)ETriggerType.Critical,arg);
            }
            else if (type == ETransmitType.Dead)
            {
                Trigger((int)ETriggerType.Dead,arg);
            }
            else if (type == ETransmitType.UnitBorn)
            {
                //Trigger((int)ETriggerType.Halo,arg);
                if (arg is UnitBornArg bArg && PveManager.Instance.rpgStart)
                {
                    Trigger((int)ETriggerType.Halo,arg);
                    if (bArg.unit == this.unit)
                    {
                        Trigger((int)ETriggerType.BattleStart,arg);
                    }
                }
            }
            else if (type == ETransmitType.ShootHit)
            {
                Trigger((int) ETriggerType.ShootHit, arg,true);
            }
            else if (type == ETransmitType.GetShootHit)
            {
                getShootTimes++;
                Trigger((int) ETriggerType.GetShootHit, arg,true);
            }
            else if (type == ETransmitType.NormalUnitDead)
            {
                Trigger((int) ETriggerType.NormalUnitDead,arg);
            }
            /*else if (type == ETransmitType.CreateBullet)
            {
                Trigger((int)ETriggerType.CreateBullet);
            }*/
            /*else if (type == ETransmitType.OnInitiativeSkillEnd)
            {
                Trigger((int)ETriggerType.InitiativeSkillEnd);
            }
            else if (type == ETransmitType.OnAutoSkillEnd)
            {
                Trigger((int)ETriggerType.AutoSkillEnd);
            }*/
            else if (type == ETransmitType.OnSkillEnd)
            {
                var argg = arg as SkillEndArg;
                if (argg.skill is SkillInitiative)
                {
                    Trigger((int)ETriggerType.InitiativeSkillEnd);
                }
                else if (argg.skill is SkillAuto)
                {
                    Trigger((int)ETriggerType.AutoSkillEnd);
                }
            }
        }

        private int lastEnemyBesideCount;

        public void Update()
        {
            //每帧需要检查的被动技能
            if (!PveManager.Instance.rpgStart)
            {
                return;
            }
            for (int i = 0; i < everyFrameCheckList.Count; i++)
            {
                //13.附近敌人数量
                if (everyFrameCheckList[i].trigger_type == 13)
                {
                    var list = UnitManager.Instance.GetAllUnitByTeam(unit.Data.GetTargetTeam(unit.Data.searchType));
                    int count = 0;
                    for (int j = 0; j < list.Count; j++)
                    {
                        if (Vector3.Distance(list[j].Data.position, unit.Data.position) < everyFrameCheckList[i].GetTriggerParam(1))
                        {
                            count++;
                        }
                    }

                    if (count >= everyFrameCheckList[i].GetTriggerParam(0))
                    {
                        Trigger((int) ETriggerType.EnemyBeside);
                    }

                    lastEnemyBesideCount = count;
                }
                else if (everyFrameCheckList[i].trigger_type == 15)
                {
                    Trigger((int) ETriggerType.CheckEveryFrame);
                }
                else if (everyFrameCheckList[i].trigger_type == (int) ETriggerType.BattleStart)
                {
                    if (CheckIsInBornCd(everyFrameCheckList[i]))
                    {
                        Trigger((int)ETriggerType.BattleStart);
                        everyFrameCheckList.RemoveAt(i);
                        i--;
                    }
                }
            }
            
        }

        private bool CheckIsInBornCd(PveSkillConfig config)
        {
            return TimeManager.logicTime - bornTime < config.born_cd;
        }

        private bool CheckIsInSkillCd(SkillBase skill)
        {
            return skill.startTime != 0 && TimeManager.logicTime - skill.startTime < skill.config.cd;
        }

        private bool CheckIsHit(int skillId,UnitData unitData,int level)
        {
            var chance = PveTriggerChanceFunction.GeTriggerChance(skillId,unitData,level);
            if (chance == 0)
            {
                chance = 1;
            }
            return Random.Range(0, 1f) <= chance;
        }

        private void Trigger(int triggerType,BaseTransmitArg arg = null,bool needCheckProbability = true)
        {
            if (triggerType == (int) ETriggerType.BattleStart)
            {
                bornTime = TimeManager.logicTime;
            }
            elementSystem?.Trigger(triggerType);
            if (PveManager.Instance.isInPve || unit.Data.isManualMoving || (triggerType != (int)ETriggerType.Dead && unit.Data.isDead))
            {
                return;
            }

            foreach (var item in skills.Values)
            {
                if (triggerType != item.config.trigger_type)
                {
                    continue;
                }

                if (CheckIsInSkillCd(item))
                {
                    continue;
                }

                if (CheckIsInBornCd(item.config))
                {
                    if (triggerType == (int) ETriggerType.BattleStart)
                    {
                        if (!everyFrameCheckList.Contains(item.config))
                        {
                            everyFrameCheckList.Add(item.config);
                        }
                    }
                    continue;
                }
                
                bool isHit = !needCheckProbability || CheckIsHit(item.config.id,unit.Data,item.level);
                if (triggerType == (int) ETriggerType.HpLost && isHit)
                {
                    isHit = false;
                    if (hpLostLines.TryGetValue(item.config.id, out var hpList))
                    {
                        var currentPercent = unit.Data.CurrentHp / unit.Data.TotalHp;
                        for (int i = 0; i < hpList.Count; i++)
                        {
                            if (hpList[i] >= currentPercent)
                            {
                                isHit = true;
                                hpList.RemoveAt(i);
                                break;
                            }
                        }
                    }
                }
                else if (triggerType == (int) ETriggerType.GetShootHit)
                {
                    if (getShootTimes >= item.config.GetTriggerParam())
                    {
                        getShootTimes = 0;
                    }
                    else
                    {
                        isHit = false;
                    }
                }
                else if (triggerType == (int) ETriggerType.Shoot)
                {
                    if (shootTimes >= item.config.GetTriggerParam())
                    {
                        shootTimes = 0;
                    }
                    else
                    {
                        isHit = false;
                    }
                }
                else if (triggerType == (int) ETriggerType.NormalUnitDead)
                {
                    var sarg = arg as NormalUnitDeadArg;
                    if (sarg.team != unit.Data.team)//暂时变为敌方死亡时
                    {
                        isHit = true;
                    }
                    else
                    {
                        isHit = false;
                    }
                }
                else if (triggerType == (int) ETriggerType.SummonOnly)
                {
                    isHit = unit.Data.summonUnit == null || unit.Data.summonUnit.Data.isDead;
                }
                if (isHit)
                {
                    
                    if (item is SkillAuto)
                    {
                        if (!readyList.Contains(item))
                        {
                            readyList.Add(item);
                        }
                    }
                    else
                    {
                        List<UnitBase> targetUnits = null;
                        if (triggerType == (int)ETriggerType.GetHit)
                        {
                            var targetUnit = (arg as BeHitByOthersArg).source;
                            targetUnits = new List<UnitBase> {targetUnit};
                        }
                        else if (triggerType == (int) ETriggerType.GetShootHit)
                        {
                            //if (item.config.search_team == 0)
                            {
                                var targetUnit = (arg as BeHitByOthersArg).source;
                                targetUnits = new List<UnitBase> {targetUnit};
                            }
                        }
                        else if (triggerType == (int) ETriggerType.Halo)
                        {
                            if (arg is UnitBornArg uArg)
                            {
                                targetUnits = new List<UnitBase> {uArg.unit};
                            }
                            else
                            {
                                targetUnits = new List<UnitBase>();
                                PveTargetSearchHelper.GetCandidates(unit,item.config,ref targetUnits); 
                            }

                            for (int j = 0; targetUnits != null && j < targetUnits.Count; j++)
                            {
                                if (!PveTargetSearchHelper.CheckIsInTagList(unit, targetUnits[j], item.config))
                                {
                                    targetUnits.RemoveAt(j);
                                    j--;
                                }
                            }

                            if (targetUnits == null || targetUnits.Count == 0)
                            {
                                continue;
                            }
                        }
                        else if (triggerType == (int) ETriggerType.ShootHit)
                        {
                            //if (item.config.search_type == 0)
                            {
                                targetUnits = new List<UnitBase> {unit.Data.lockTarget};
                            }
                        }
                        item.Play(unit.Data.position,unit.Data.forward,targetUnits,true);
                    }
                    //item.Play(unit.Data.position,unit.Data.forward); //(skillArg.targetForward);
                }
            }
            
            //先检查普攻序列是否含有元素
            if (triggerType == (int) ETriggerType.BeforeAttack && readyList.Count == 0)
            {
                if (unit.Data.attackSequenceSkills.Count > 0)
                {
                    int currentSkillId = unit.Data.attackSequenceSkills[currentAttackSequenceIndex];
                    if (currentSkillId > 0 && attackSequenceSkills.TryGetValue(currentSkillId,out var skill))
                    {
                        readyList.Add(skill);
                    }

                    currentAttackSequenceIndex++;
                    if (currentAttackSequenceIndex >= unit.Data.attackSequenceSkills.Count)
                    {
                        currentAttackSequenceIndex = 0;
                    }
                }
            }
        }
    }
}